package com.wzdigit.wms.wms.service.transfer;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wzdigit.framework.Shift;
import com.wzdigit.mes.basic.api.BasicDataItemDetailApi;
import com.wzdigit.mes.basic.api.BasicSimpleCodeRuleApi;
import com.wzdigit.wms.basic.client.Pager;
import com.wzdigit.wms.basic.client.PagerInfo;
import com.wzdigit.wms.basic.client.request.transfer.SubmitTransferDtlGoodsRequest;
import com.wzdigit.wms.basic.client.request.transfer.SubmitTransferRequest;
import com.wzdigit.wms.basic.client.response.Result;
import com.wzdigit.wms.basic.client.response.transfer.TransferDtlGoodsResponse;
import com.wzdigit.wms.basic.client.response.transfer.TransferHeaderPageResponse;
import com.wzdigit.wms.basic.client.response.transfer.TransferHeaderResponse;
import com.wzdigit.wms.basic.domain.dtos.inventory.UpdateInventoryInputDto;
import com.wzdigit.wms.basic.domain.inventory.Goods;
import com.wzdigit.wms.basic.domain.inventory.GoodsLog;
import com.wzdigit.wms.basic.domain.inventory.InvTrans;
import com.wzdigit.wms.basic.domain.mid.IfPostback;
import com.wzdigit.wms.basic.domain.order.TrsnDtl;
import com.wzdigit.wms.basic.domain.order.TrsnDtlGoods;
import com.wzdigit.wms.basic.domain.order.TrsnHeader;
import com.wzdigit.wms.basic.domain.transfer.TransferDtl;
import com.wzdigit.wms.basic.domain.transfer.TransferDtlGoods;
import com.wzdigit.wms.basic.domain.transfer.TransferHeader;
import com.wzdigit.wms.basic.enums.*;
import com.wzdigit.wms.basic.mapper.core.transfer.TransferDtlGoodsMapper;
import com.wzdigit.wms.basic.mapper.core.transfer.TransferDtlMapper;
import com.wzdigit.wms.basic.mapper.core.transfer.TransferHeaderMapper;
import com.wzdigit.wms.basic.util.HttpSessionUtil;
import com.wzdigit.wms.basic.util.StringUtils;
import com.wzdigit.wms.common.entity.StatusCode;
import com.wzdigit.wms.wms.service.basic.LocationService;
import com.wzdigit.wms.wms.service.basic.WarehouseService;
import com.wzdigit.wms.wms.service.core.GoodsService;
import com.wzdigit.wms.basic.service.code.InventoryService;
import com.wzdigit.wms.wms.service.core.trsn.TrsnDtlGoodsService;
import com.wzdigit.wms.wms.service.core.trsn.TrsnDtlService;
import com.wzdigit.wms.wms.service.core.trsn.TrsnHeaderService;
import com.wzdigit.wms.wms.service.mid.IfPostbackService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 转仓接收--服务类
 * @author yangdongjie
 * @TurnWshReceivedService.java
 * @2021年1月26日上午10:21:12
 */
@Service
public class TurnWshReceivedService {

	@Autowired
	private TransferDtlGoodsMapper transferDtlGoodsMapper;
	
	@Autowired
	private TransferHeaderMapper transferHeaderMapper;

	@Autowired
	private TransferDtlMapper transferDtlMapper;
	
	@Autowired
	private WarehouseService warehouseService;
	
	@Autowired
	private InventoryService inventoryService;
	
	@Autowired
	private GoodsService goodsService;
	
    @Autowired
    private TrsnDtlService trsnDtlService;
    
    @Autowired
    private LocationService locationService;
    
    @Autowired
    private TrsnHeaderService trsnHeaderService;

    @Autowired
    private TrsnDtlGoodsService trsnDtlGoodsService;
    
    @Autowired
    @Lazy
    private IfPostbackService ifPostbackService;
    
    @Autowired
    private TransferTaskService transferTaskService;
    
	@Value("${order_type.transfer.dictionary_code}")
    private String dictionaryCode;
	
	@Value("${order_type.transfer.ptyb}")
	private String ptyb;
	
	@Value("${order.code.transfer}")
	private String transferCode;
	
    @Reference(version = "${dubbo.consumers.basic.data.item.detail.api:1.0.0}", check = false)
    private BasicDataItemDetailApi basicDataItemDetailApi;

    @Reference(version = "${dubbo.consumers.basic.simple.code.rule.api:1.0.0}", check = false)
    private BasicSimpleCodeRuleApi basicSimpleCodeRuleApi;

    private static final String TRSN_ORDER = "TRSN_ORDER";
    
	/**
	 * 转仓单列表
	 * @param transferNo
	 * @param pager
	 * @param servletRequest
	 * @return
	 */
	public PagerInfo<List<TransferHeaderPageResponse>> searchTransfer(
			String transferNo, Pager<?> pager,
			HttpServletRequest servletRequest) {
		List<Integer> wareHouseIds = warehouseService.getWareHouseIds(servletRequest);
		
		if (StringUtils.isNotNull(transferNo)) {
			// 校验转仓单号是否存在
			QueryWrapper<TransferHeader> transferHeaderWrapper = new QueryWrapper<>();
			transferHeaderWrapper.eq("TRANSFER_NO", transferNo);
			TransferHeader one = transferHeaderMapper.selectOne(transferHeaderWrapper);
			if (one == null) {
				// 调拨单不存在
				Shift.fatal(StatusCode.TRANSFER_DTL_NULL);
			} else {
				if(one.getStatus() != TransferHeaderStatusEnum.CREATE.code) {
					// 调拨单不是创建状态
					Shift.fatal(StatusCode.TRANSFER_DTL_SUBMITED);
				}
			}
		}
		
		Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());

		PagerInfo<List<TransferHeaderPageResponse>> pagerInfo = new PagerInfo<List<TransferHeaderPageResponse>>();
		List<TransferHeaderPageResponse> datas = transferHeaderMapper.getListPage(
				TransferTypeEnum.T01.code, TransferHeaderStatusEnum.CREATE.code,
				transferNo, wareHouseIds);
		if (page.getTotal() == 0) {
			if (StringUtils.isNotNull(transferNo)) {
				// 没有该单据所在仓库的权限，请联系管理员
				Shift.fatal(StatusCode.TRANSFER_NULL_WHS1);
			} else {
				// 没有当前账号权限的仓库的转仓单数据，请联系管理员
				Shift.fatal(StatusCode.TRANSFER_NULL_WHS2);
			}
		}
		pagerInfo.setItems(datas);
		pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}

	/**
	 * 转仓单详情
	 * @param goodsSn
	 * @param transferNo
	 * @param servletRequest
	 * @return
	 */
	public TransferHeaderResponse getTransfer(String goodsSn, String transferNo, HttpServletRequest servletRequest) {
		if (goodsSn == null && transferNo == null) {
			Shift.fatal(StatusCode.INVALID_PARAMS_MUST);
		}
		List<Integer> wareHouseIdList = warehouseService.getWareHouseIds(servletRequest);
		
		if (transferNo == null) {
			// 校验SN是否存在
			QueryWrapper<TransferDtlGoods> transferDtlGoodsWrapper = new QueryWrapper<>();
			transferDtlGoodsWrapper.eq("GOODS_SN", goodsSn);
			TransferDtlGoods goods = transferDtlGoodsMapper.selectOne(transferDtlGoodsWrapper);
			if (goods == null) {
				Shift.fatal(StatusCode.NOT_GOOD_SN);
			}
			TransferDtl transferDtl = transferDtlMapper.selectById(goods.getTransferDtlId());
			transferNo = transferDtl.getTransferNo();
		}
		
		// 校验转仓单号是否存在
		QueryWrapper<TransferHeader> transferHeaderWrapper = new QueryWrapper<>();
		transferHeaderWrapper.eq("TRANSFER_NO", transferNo);
		TransferHeader transferHeader = transferHeaderMapper.selectOne(transferHeaderWrapper);
		if (transferHeader == null) {
			Shift.fatal(StatusCode.TRANSFER_DTL_NULL);
		} else {
			if(!Objects.equals(TransferHeaderStatusEnum.CREATE.code, transferHeader.getStatus())) {
				// 调拨单不是创建状态
				Shift.fatal(StatusCode.TRANSFER_DTL_SUBMITED);
			}
		}
		
		TransferHeaderResponse vo = transferHeaderMapper.getOneByTransferNo(transferNo, wareHouseIdList);
		if (vo == null) {
			Shift.fatal(StatusCode.TRANSFER_NULL_WHS1);
		}
		
		List<TransferDtlGoodsResponse> transferDtlGoodsList = transferDtlGoodsMapper.selectAll(vo.getTransferHeaderId(), TransferDtlStatusEnum.CREATE.code, TransferDtlStatusEnum.CLOSE.code);
		Map<String, List<TransferDtlGoodsResponse>> groupMap = transferDtlGoodsList.stream().collect(Collectors.groupingBy(t -> (t.getSkuId() + "#" + t.getPoNo()), Collectors.toList()));
		for (String groupKey : groupMap.keySet()) {
			List<TransferDtlGoodsResponse> itemList = groupMap.get(groupKey);
			TransferDtlGoodsResponse item = itemList.get(0);
			String recommendedLocation = locationService.selectRecommendedUpLocation(item.getSkuId(), vo.getToWhsId(), item.getPoNo());
			itemList.stream().forEach(t -> {
				t.setRecommendedLocation(recommendedLocation);
			});
		}
		vo.setTransferDtlGoodsList(transferDtlGoodsList);
		return vo;
	}
	
	/**
	 * 转仓单点收
	 * 1> 源仓库【预支数量】减少，【数量】减少，
	 * 2> 目的仓库【预售数量】减少，【数量】增加。
	 * 3> 调【生成库存日志】服务
	 * 4> 调【更新货品】服务，变更产品SN状态。调【生成SN操作日志】服务
	 * 5> 调【生成出入库凭证】服务
	 * 6> 转仓单状态变更
	 * @throws Exception 
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public synchronized Result<?> submitTransfer(SubmitTransferRequest dto, 
			HttpServletRequest servletRequest) throws Exception {
		// 转仓单表头
		TransferHeader header = transferHeaderMapper.selectById(dto.getTransferHeaderId());
		if(header.getStatus() != TransferHeaderStatusEnum.CREATE.code) {
			// 调拨单不是创建状态
			Shift.fatal(StatusCode.TRANSFER_DTL_SUBMITED);
		}
		
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
        Date localDate = new Date();
        
        
        // 分组【转仓单明细ID -> 转仓单货品清单ID集合】
		Map<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
		List<SubmitTransferDtlGoodsRequest> list = dto.getDtlGoodsList();
		list.forEach(one -> {
			List<Integer> dtlIds = map.get(one.getTransferDtlId());
			if (dtlIds == null) {
				dtlIds = new ArrayList<Integer>();
				map.put(one.getTransferDtlId(), dtlIds);
			}
			dtlIds.add(one.getTransferGoodsId());
		});
		
		// 是否更新 【调拨单表头】 状态标识
		boolean falg = false;
		
		// 遍历点收转仓单明细
		for (Integer transferDtlId : map.keySet()) {
			// 有效的转仓单货品清单集合-->【待接收】
			QueryWrapper<TransferDtlGoods> transferDtlGoodsWrapper = new QueryWrapper<>();
			transferDtlGoodsWrapper.in("TRANSFER_GOODS_ID", map.get(transferDtlId));
			transferDtlGoodsWrapper.eq("STATUS", TransferDtlGoodStatusEnum.WAIT_RECEIVE.code);	// 待接收
			List<TransferDtlGoods> dtlGoodsList = transferDtlGoodsMapper.selectList(transferDtlGoodsWrapper);
			
			// 有效的转仓单货品清单数量大于零-->可进行接收
			if (dtlGoodsList.size() > 0) {
					falg = true;
				
				// 库存交易凭证表头状态-->【进行中】
				Integer trsnHeaderStatus = null;
				
				// 库存交易凭证明细状态-->【进行中】
				Integer trsnDtlStatus = null;
				
				// 有效的转仓单货品清单ID集合
				List<Integer> dtlGoodsIds = dtlGoodsList.stream().map(TransferDtlGoods::getTransferGoodsId)
						.collect(Collectors.toList());

				// 批量修改SN状态为已完成
				transferDtlGoodsMapper.updateStatus(localDate, loginName, dtlGoodsIds);

				// 更新转仓单明细【实收数、状态】
				TransferDtl transferDtl = transferDtlMapper.selectById(transferDtlId);
				
				transferDtl.setCmpQty(transferDtl.getCmpQty() + dtlGoodsList.size());
				transferDtl.setModifyTime(localDate);
				transferDtl.setModifyUser(loginName);
				if (transferDtl.getOrderQty().equals(transferDtl.getCmpQty())) {
					transferDtl.setStatus(TransferDtlStatusEnum.CLOSE.code); 	// 关闭
					trsnHeaderStatus = TrsnHeaderStatusEnum.CMP.code;			// 完成
					trsnDtlStatus = TrsnDtlStatusEnum.CMP.code;					// 完成
				} else {
					transferDtl.setStatus(TransferDtlStatusEnum.DOING.code); 	// 进行中
					trsnHeaderStatus = TrsnHeaderStatusEnum.PRC.code;		 	// 进行中
					trsnDtlStatus = TrsnDtlStatusEnum.PRC.code;				 	// 进行中
				}
				transferDtlMapper.updateById(transferDtl);

				// 更新库存
				inventory(header, transferDtl, dtlGoodsList, loginName, 
						localDate, trsnHeaderStatus, trsnDtlStatus);
			}
		}
		
		// 更新 【调拨单表头】 状态
		if(falg) {
			QueryWrapper<TransferDtl> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("TRANSFER_HEADER_ID", dto.getTransferHeaderId());
			queryWrapper.ge("STATUS", TransferDtlStatusEnum.CREATE.code);	// 创建
			queryWrapper.le("STATUS", TransferDtlStatusEnum.DOING.code);	// 进行中
			if(transferDtlMapper.selectCount(queryWrapper) == 0) {
				header.setStatus(TransferHeaderStatusEnum.CLOSE.code); // 完成
				transferHeaderMapper.updateEndTime(dto.getTransferHeaderId());
			} else {
				header.setStatus(TransferHeaderStatusEnum.DOING.code); 	// 进行中
			}
			header.setModifyTime(localDate);
			header.setModifyUser(loginName);
			header.setToBusinessMan(loginName);
			header.setTransferCmpTime(localDate);
			transferHeaderMapper.updateById(header);
		}
		
		// 转仓接收调SAP调拨接口
        IfPostback ifPostback = transferTaskService.insertIfpostbackList(loginName, header, TransferTypeEnum.T01.code);
        // 新增到WMS_IF_POSTBACK
        ifPostbackService.addOne(ifPostback);
		return new Result<>();
	}
	
	// 更新库存
	public void inventory(TransferHeader header, TransferDtl dtl,
			List<TransferDtlGoods> dtlGoodsList, String loginName, Date localDate, 
			Integer trsnHeaderStatus, Integer trsnDtlStatus) throws Exception {
		BigDecimal zero = BigDecimal.ZERO;
		int size = dtlGoodsList.size();
		// 来源仓
		UpdateInventoryInputDto source = new UpdateInventoryInputDto();
		source.setOperator(loginName);
		source.setWhsId(header.getFmWhs()); // 来源仓库

		source.setSkuId(dtl.getFmSku()); // 物料ID
		source.setOwner(dtl.getFmOwner()); // 货主ID
		source.setLotNo(dtl.getFmLotno()); // 内部批次号
		source.setFactory(dtl.getFmFactory()); // 工厂
		source.setInvAttr(dtl.getFmInvAttr()); // 库存性质
		source.setVendorId(dtl.getFmVendor()); // 供应商ID
		source.setQaStatus(dtl.getFmQaStatus());// 品质状态

		source.setUnit(dtl.getUnit()); // 单位
		source.setQty(new BigDecimal(size).negate()); // 数量【-】
		source.setPreOutQty(new BigDecimal(size).negate()); // 预支数量【-】

		source.setAlocQty(zero); 	// 分配数量
		source.setHoldQty(zero); 	// 冻结数量
		source.setPreInQty(zero); 	// 预收数量
		source.setPreAlocQty(zero);// 预分配数量

		// 来源仓日志
		InvTrans sourceInvTrans = new InvTrans();
		sourceInvTrans.setOperator(loginName);
		sourceInvTrans.setCreateTime(localDate);
		sourceInvTrans.setCreateUser(loginName);
		
		sourceInvTrans.setFmUnit(dtl.getUnit()); 				// 单位
		sourceInvTrans.setFmSkuId(dtl.getFmSku());
		sourceInvTrans.setFmOwner(dtl.getFmOwner());
		sourceInvTrans.setDocLineNo(dtl.getTransferLineNo()); 	// 单据行号

		sourceInvTrans.setFmWhsId(header.getFmWhs());
		sourceInvTrans.setDocNo(header.getTransferNo());
		sourceInvTrans.setDocType(header.getTransferType());
		sourceInvTrans.setTransTime(header.getTransferCreateTime());
		
		sourceInvTrans.setOpCode(OpCodeEnum.TRANSFEROUT.getCode());
		sourceInvTrans.setStatus(InvTransStatusEnum.FINISHED.code);
		
		sourceInvTrans.setFmQty(source.getQty()); 				// 数量
		sourceInvTrans.setFmPreOutQty(source.getPreOutQty()); 	// 预支数量
		inventoryService.inventoryOut(source, sourceInvTrans);

		// 目的仓
		UpdateInventoryInputDto target = new UpdateInventoryInputDto();
		target.setOperator(loginName);
		target.setWhsId(header.getToWhs());

		target.setSkuId(dtl.getToSku()); // 物料ID
		target.setOwner(dtl.getToOwner()); // 货主ID
		target.setLotNo(dtl.getToLotno()); // 内部批次号
		target.setFactory(dtl.getToFactory()); // 工厂
		target.setInvAttr(dtl.getToInvAttr()); // 库存性质
		target.setVendorId(dtl.getToVendor()); // 供应商ID
		target.setQaStatus(dtl.getToQaStatus());// 品质状态

		target.setUnit(dtl.getUnit()); // 单位
		target.setQty(new BigDecimal(size)); // 数量【+】
		target.setPreInQty(new BigDecimal(size).negate()); // 预收数量【-】

		target.setHoldQty(zero); 	// 冻结
		target.setAlocQty(zero); 	// 分配数量
		target.setPreOutQty(zero); 	// 预支数量
		target.setPreAlocQty(zero);	// 预配数量

		// 目的仓日志
		InvTrans targetInvTrans = new InvTrans();
		targetInvTrans.setOperator(loginName);
		targetInvTrans.setCreateUser(loginName);
		targetInvTrans.setCreateTime(localDate);
		
		targetInvTrans.setToUnit(dtl.getUnit()); // 单位
		targetInvTrans.setToSkuId(dtl.getToSku());
		targetInvTrans.setToOwner(dtl.getToOwner());
		targetInvTrans.setDocLineNo(dtl.getTransferLineNo()); // 单据行号

		targetInvTrans.setToWhsId(header.getToWhs());
		targetInvTrans.setDocNo(header.getTransferNo());
		targetInvTrans.setDocType(header.getTransferType());
		targetInvTrans.setTransTime(header.getTransferCreateTime());

		targetInvTrans.setOpCode(OpCodeEnum.TRANSFERIN.getCode());
		targetInvTrans.setStatus(InvTransStatusEnum.FINISHED.code);

		targetInvTrans.setToQty(target.getQty()); 			// 数量
		targetInvTrans.setToPreInQty(target.getPreInQty()); // 预收数量
		inventoryService.inventoryIn(target, targetInvTrans);
		
		// 变更产品SN状态
		List<TrsnDtlGoods> trsnDtlGoodsList = goodsSn(loginName, localDate, 
				header.getToWhs(), dtlGoodsList);
				
		Class<?> dtlClass = dtl.getClass();
		
		// 库存交易凭证明【源仓库】=出库单
		TrsnHeader sourceTrsnHeader = new TrsnHeader();
		String sourceTrsnNoteNo = basicSimpleCodeRuleApi.GenerateCode(TRSN_ORDER);
		sourceTrsnHeader.setNoteType(TrsnNoteTypeEnum.OUT_STORAGE.getCode());
		sourceTrsnHeader.setStatus(trsnHeaderStatus);
		sourceTrsnHeader.setNoteNo(sourceTrsnNoteNo);
		sourceTrsnHeader.setOwner(dtl.getFmOwner());
		sourceTrsnHeader.setFactory(dtl.getFmFactory());
		sourceTrsnHeader.setWhsId(header.getFmWhs());
		sourceTrsnHeader.setVendorId(dtl.getFmVendor());
		sourceTrsnHeader.setFmDoc(dtl.getTransferNo());
		sourceTrsnHeader.setCreateTime(localDate);
		sourceTrsnHeader.setCreateUser(loginName);
		trsnHeaderService.addNewOne(sourceTrsnHeader);
		
		TrsnDtl sourceTrsnDtl = new TrsnDtl();
		sourceTrsnDtl.setNoteLineNo("1");							// 凭证行号
		sourceTrsnDtl.setInvUpdateFlag(TrsnDtlInvUpdateFlagEnum.OUT.code);// 出库
		sourceTrsnDtl.setStatus(trsnDtlStatus);
		sourceTrsnDtl.setUnit(dtl.getUnit());						// 单位
		sourceTrsnDtl.setSkuId(dtl.getFmSku());						// 货品
		sourceTrsnDtl.setQty(new BigDecimal(size));					// 数量
		sourceTrsnDtl.setFmDoc(dtl.getTransferNo());				// 源单号
		sourceTrsnDtl.setQaStatus(dtl.getFmQaStatus());				// 品质状态：待检、合格、不合格
		sourceTrsnDtl.setFmDocLine(dtl.getTransferLineNo());		// 源单行号
		sourceTrsnDtl.setNoteNo(sourceTrsnHeader.getNoteNo()); 		// 凭证号
		sourceTrsnDtl.setTrsnHeaderId(sourceTrsnHeader.getTrsnHeaderId());
		sourceTrsnDtl.setCreateTime(localDate);
		sourceTrsnDtl.setCreateUser(loginName);
		Class<?> sourceTrsnDtlClass = sourceTrsnDtl.getClass();
		for (int i = 1; i < 13; i++) {
			Field field = dtlClass.getDeclaredField("fmLotAttr" + i);
			Method method = sourceTrsnDtlClass.getMethod("setLotAttr" + i, String.class);
			field.setAccessible(true);
			method.setAccessible(true);
			method.invoke(sourceTrsnDtl, field.get(dtl));
		}
		trsnDtlService.addNewOne(sourceTrsnDtl);
		
		trsnDtlGoodsList.forEach(one -> {
			one.setTrsnDtlId(sourceTrsnDtl.getTrsnDtlId());
		});
		trsnDtlGoodsService.addNewList(trsnDtlGoodsList);
		
		// 库存交易凭证明【目的仓库】=入库单
		TrsnHeader targetTrsnHeader = new TrsnHeader();
		String targetTrsnNoteNo = basicSimpleCodeRuleApi.GenerateCode(TRSN_ORDER);
		targetTrsnHeader.setNoteType(TrsnNoteTypeEnum.IN_STORAGE.getCode());
		targetTrsnHeader.setStatus(trsnHeaderStatus);
		targetTrsnHeader.setNoteNo(targetTrsnNoteNo);
		targetTrsnHeader.setOwner(dtl.getToOwner());
		targetTrsnHeader.setFactory(dtl.getToFactory());
		targetTrsnHeader.setWhsId(header.getToWhs());
		targetTrsnHeader.setVendorId(dtl.getToVendor());
		targetTrsnHeader.setFmDoc(dtl.getTransferNo());
		targetTrsnHeader.setCreateTime(localDate);
		targetTrsnHeader.setCreateUser(loginName);
		trsnHeaderService.addNewOne(targetTrsnHeader);
		
		TrsnDtl targetTrsnDtl = new TrsnDtl();
		targetTrsnDtl.setNoteLineNo("1");							// 凭证行号
		targetTrsnDtl.setInvUpdateFlag(TrsnDtlInvUpdateFlagEnum.IN.code);// 入库
		targetTrsnDtl.setStatus(trsnDtlStatus);
		targetTrsnDtl.setUnit(dtl.getUnit());						// 单位
		targetTrsnDtl.setSkuId(dtl.getToSku());						// 货品
		targetTrsnDtl.setQty(new BigDecimal(size));					// 数量
		targetTrsnDtl.setFmDoc(dtl.getTransferNo());				// 源单号
		targetTrsnDtl.setQaStatus(dtl.getToQaStatus());				// 品质状态：待检、合格、不合格
		targetTrsnDtl.setFmDocLine(dtl.getTransferLineNo());		// 源单行号
		targetTrsnDtl.setNoteNo(targetTrsnHeader.getNoteNo()); 		// 凭证号
		targetTrsnDtl.setTrsnHeaderId(targetTrsnHeader.getTrsnHeaderId());
		targetTrsnDtl.setCreateTime(localDate);
		targetTrsnDtl.setCreateUser(loginName);
		Class<?> targetTrsnDtlClass = targetTrsnDtl.getClass();
		for (int i = 1; i < 13; i++) {
			Field field = dtlClass.getDeclaredField("toLotAttr" + i);
			Method method = targetTrsnDtlClass.getMethod("setLotAttr" + i, String.class);
			field.setAccessible(true);
			method.setAccessible(true);
			method.invoke(targetTrsnDtl, field.get(dtl));
		}
		trsnDtlService.addNewOne(targetTrsnDtl);
		
		trsnDtlGoodsList.forEach(one -> {
			one.setTrsnDtlId(targetTrsnDtl.getTrsnDtlId());
		});
		trsnDtlGoodsService.addNewList(trsnDtlGoodsList);
	}
	
	// 变更产品SN状态
	private List<TrsnDtlGoods> goodsSn(String loginName, Date localDate, 
			Integer whsId, List<TransferDtlGoods> dtlGoodsList) {
		List<TrsnDtlGoods> trsnDtlGoodsList = new ArrayList<>();
		
		for (TransferDtlGoods transferDtlGood : dtlGoodsList) {
			Goods goods = goodsService.selectByGoodsId(transferDtlGood.getGoodsId());
			String oldGoodsJson = JSON.toJSONString(goods); // 原先的json

			goods.setLocId(null);							// 库位置空
			goods.setWhsId(whsId);							// 改成目的仓
			goods.setStatus(GoodsStatusEnum.WAIT_UP.code); 	// 待上架
			goods.setModifyUser(loginName);
			goods.setModifyTime(localDate);
			
			// 更新仓库、库位、状态
			goodsService.updateWhsIdAndLocIdAndStatusById(goods);
			
			String newGoodsJson = JSON.toJSONString(goods); // 更新后的json

			// 生成SN操作日志
			GoodsLog goodsLog = new GoodsLog();
			goodsLog.setOpCode(OpCodeEnum.TRANSFERIN.getCode());
			goodsLog.setOperator(loginName);
			goodsLog.setCreateUser(loginName);
			goodsLog.setCreateTime(localDate);
			goodsLog.setGoodsSn(transferDtlGood.getGoodsSn());

			goodsLog.setUpdateContent("未更新的:" + oldGoodsJson + ",更新的:" + newGoodsJson);
			goodsService.insertGoodsLog(goodsLog);
			
			// 库存交易凭证明细货品清单
			TrsnDtlGoods trsnDtlGoods = new TrsnDtlGoods();
			trsnDtlGoods.setGoodsSn(transferDtlGood.getGoodsSn());
			trsnDtlGoods.setGoodsId(transferDtlGood.getGoodsId());
			trsnDtlGoods.setQty(transferDtlGood.getQty());
			trsnDtlGoods.setQaStatus(transferDtlGood.getQaStatus());
			trsnDtlGoods.setStatus(TransferDtlGoodStatusEnum.HAS_RECEIVE.code);
			trsnDtlGoods.setCreateUser(loginName);
			trsnDtlGoods.setCreateTime(localDate);
			trsnDtlGoodsList.add(trsnDtlGoods);
		}
		return trsnDtlGoodsList;
	}
}
